package com.mac.bluetoothbt.feature;

import android.app.*;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.*;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.clj.fastble.BleManager;
import com.clj.fastble.callback.*;
import com.clj.fastble.data.BleDevice;
import com.clj.fastble.exception.BleException;
import com.clj.fastble.scan.BleScanRuleConfig;
import com.clj.fastble.utils.HexUtil;

import java.lang.ref.WeakReference;
import java.util.Arrays;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Timer;


/**
 * @author wyh
 */
public class FastBleService extends Service {
    public static final int RECEIVEBUFFER_LENGTH = DeviceEntity.BUFFERLENGTH;
    //发送延时
    //public static final int MILLIS = 400;
    private List<BluetoothGattService> localservices = null;
    private BleDevice localBleDevice = null;
    private BluetoothGattService localService = null;
    private BluetoothGattCharacteristic localCharacteristic = null;
    private byte[] receivedata = new byte[RECEIVEBUFFER_LENGTH];
    private int runner = 0;
    private boolean stopread = true;
    private static final Timer timer = new Timer();
    public static byte[] backData;
    /**
     * 定时读寄存器暂停
     */
    private static boolean isStateUpdateStoped = false;
    private BluetoothServiceReceiver bluetoothServiceReceiver;
    public static Queue<WriteWithCallback> sendMsgQueue = new LinkedList<>();
    /**
     * 用于识别通知
     */
    public static final String CHANNEL_ID = "BLE FOREGROUND SERVICE CHANNEL";
    private String macToLink;
    public static boolean isBtConnected = false;


    @Override
    public void onCreate() {
        startScan();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Actions.ACTION_LINKBT_MAC);
        filter.addAction(Actions.ACTION_REQUEST_LOCATION_PERMISSION_SUCCESS);
        filter.addAction(Actions.ACTION_TIMER_TRIG);
        filter.addAction(Actions.ACTION_SERVICE_SELECTED);
        filter.addAction(Actions.ACTION_CHAR_SELECTED);
        filter.addAction(Actions.ACTION_WRITE);
        filter.addAction(Actions.ACTION_READ);
        filter.addAction(Actions.ACTION_GETPASSWORD);
        filter.addAction(Actions.ACTION_SETTING);
        filter.addAction(Actions.ACTION_STARTSCAN);
        filter.addAction(Actions.ACTION_BLE_DISCONNECT);
        filter.addAction(Actions.ACTION_RECONNECT);
        filter.addAction(Actions.ACTION_STARTREAD);
        filter.addAction(Actions.ACTION_STOPREAD);
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        filter.addAction(Actions.ACTION_FIRST_READ);
        bluetoothServiceReceiver = new BluetoothServiceReceiver();
        registerReceiver(bluetoothServiceReceiver, filter);
    }

    /**
     * 开始扫描蓝牙
     */
    private void startScan() {
        BleManager.getInstance().init(getApplication());
        BleManager.getInstance()
                .enableLog(true)
                .setReConnectCount(3, 5000)
                .setSplitWriteNum(20)
                .setConnectOverTime(10000)
                .setOperateTimeout(5000);
        BleManager.getInstance().enableBluetooth();
        BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder()
                .build();
        BleManager.getInstance().initScanRule(scanRuleConfig);
        BleManager.getInstance().scan(new BleScanCallback() {
            @Override
            public void onScanStarted(boolean success) {
                // 开始扫描的回调
                Log.d("开始扫描", "");
            }

            @Override
            public void onScanning(BleDevice bleDevice) {
                // 扫描到一个之前没有扫到过的设备的回调
                Log.d("扫描到新设备", bleDevice.getMac());
                boolean isAdded = ((App) getApplication()).isContained(bleDevice.getMac());
                sendBroadcast(new Intent(Actions.ACTION_SCANNING).putExtra("newdevice", bleDevice).putExtra("added", isAdded));
            }

            @Override
            public void onScanFinished(List<BleDevice> scanResultList) {
                // 扫描完成的回调，列表里将不会有重复的设备
                Log.d("扫描结束", "");

                ParcelableBleDevice parcelableBleDevice = new ParcelableBleDevice(scanResultList);
                parcelableBleDevice.setBledeviceList(scanResultList);
                sendBroadcast(new Intent(Actions.ACTION_SCANEND).putExtra("devices", parcelableBleDevice));
            }
        });
    }

    @Override
    public int onStartCommand(Intent intent, int flag, int startId) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(CHANNEL_ID,
                    "NAME", NotificationManager.IMPORTANCE_DEFAULT);
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);
        }
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, notificationIntent, 0);
        Notification notification;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            notification = new Notification.Builder(this, CHANNEL_ID)
                    .setContentTitle("")
                    .setSmallIcon(R.mipmap.bluetoothlinked)
                    //.setContentIntent(pendingIntent)
                    .build();
        } else {
            notification = new NotificationCompat.Builder(this)
                    .setContentTitle("")
                    .setSmallIcon(R.mipmap.bluetoothlinked)
                    .setContentIntent(pendingIntent)
                    .build();
        }
        startForeground(1, notification);
        return START_REDELIVER_INTENT;
    }

    @Override
    public void onDestroy() {
        unregisterReceiver(bluetoothServiceReceiver);
        stopForeground(true);
        Log.e("调试", "FastBleService IS DESTROYED!!!!!!");
    }


    /**
     * 读寄存器定时器
     */
    private class GetRemoteState extends Thread {
        /**
         * 读时隙
         */
        private static final int READ_TIME_GAP = 6000;
        boolean alive = true;

        @Override
        public void run() {
            while (alive) {
                try {
                    if (!stopread) {
                        sendBroadcast(new Intent(Actions.ACTION_TIMER_TRIG));
                    }
                    Thread.sleep(READ_TIME_GAP);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    volatile int lock = 0;
    static final int LOCK = 0, UNLOCK = 1;

    private class WriteThread extends Thread {
        //发送间隔
        private static final int WRITE_TIME_GAP = 400;
        private boolean run = true;

        public void stopThread() {
            run = false;
        }
        @Override
        public void run() {
            while (run) {
                try {
                    if (sendMsgQueue.isEmpty()) {
                        continue;
                    }
                    lock = LOCK;
                    WriteWithCallback write = sendMsgQueue.poll();
                    byte[] tosend = write.getData();
                    if (Arrays.equals(tosend, FrameUtil.READ1ST)) {
                        sendBroadcast(new Intent(Actions.ACTION_FIRST_READ));
                    }
                    if (tosend == null) {
                        Log.d("debug", "data is null");
                    }
                    BleManager.getInstance().write(localBleDevice,
                            localService.getUuid().toString(),
                            localCharacteristic.getUuid().toString(),
                            tosend,
                            new BleWriteCallback() {
                                @Override
                                public void onWriteSuccess(int current, int total, byte[] justWrite) {
                                    Log.d("发送时间", new Date(System.currentTimeMillis()).toString());
                                    Log.d("发送为", "现在:" + current
                                            + "总共:" + total + " "
                                            + HexUtil.formatHexString(justWrite));
                                    if (current == total) {
                                        lock = UNLOCK;
                                    }
                                }

                                @Override
                                public void onWriteFailure(BleException exception) {
                                    Log.d("发送失败", exception.toString());
                                    lock = UNLOCK;
                                    sendBroadcast(new Intent(Actions.ACTION_BLE_DISCONNECT));
                                }
                            });
                    if (write.isWriteEnd()) {
                        sendBroadcast(new Intent(Actions.ACTION_WRITE_END));
                    }
                    while (lock == LOCK) {
                        sleep(10);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        Thread.sleep(WRITE_TIME_GAP);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }


    /**
     * 用mac连接
     *
     * @param mac mac地址
     */
    void connectByMac(String mac) {
        BleManager.getInstance().connect(mac, new BleGattCallback() {
            @Override
            public void onStartConnect() {
                // 开始连接
                Log.d("开始链接BLE", "");
            }

            @Override
            public void onConnectFail(BleDevice bleDevice, BleException exception) {
                // 连接失败
                Log.d("链接BLE失败", "");
                sendBroadcast(new Intent(Actions.ACTION_BLE_DISCONNECT));
                sendBroadcast(new Intent(Actions.ACTION_RECONNECT));
            }

            @Override
            public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) {
                // 连接成功，BleDevice即为所连接的BLE设备
                Log.d("链接BLE成功", "");
                localBleDevice = bleDevice;
                List<BluetoothGattService> services = BleManager.getInstance().getBluetoothGattServices(bleDevice);
                localservices = services;
                sendBroadcast(new Intent(Actions.ACTION_CHAR_SELECTED).putExtra("services", getUuidFromServices(services)));
            }

            @Override
            public void onDisConnected(boolean isActiveDisConnected, BleDevice bleDevice, BluetoothGatt gatt, int status) {
                // 连接中断，isActiveDisConnected表示是否是主动调用了断开连接方法
                Log.d("BLE链接中断", isActiveDisConnected ? "主动" : "被动");
                sendBroadcast(new Intent(Actions.ACTION_BLE_DISCONNECT));
                sendBroadcast(new Intent(Actions.ACTION_RECONNECT));
            }
        });
    }

    /**
     * 获得service UUID字符串
     *
     * @param services service对象
     * @return UUID数组
     */
    private String[] getUuidFromServices(List<BluetoothGattService> services) {
        String[] uuids = new String[services.size()];
        for (int i = 0; i < services.size(); i++) {
            uuids[i] = services.get(i).getUuid().toString();
        }

        return uuids;
    }

    private String[] getUuidFromchars(List<BluetoothGattCharacteristic> chars) {
        String[] uuids = new String[chars.size()];
        for (int i = 0; i < chars.size(); i++) {
            uuids[i] = chars.get(i).getUuid().toString();
        }

        return uuids;
    }

    @Override
    public IBinder onBind(Intent arg) {
        return new LocalBinder();
    }

    private final class LocalBinder extends Binder {

    }

    /**
     * 写寄存器
     *
     * @param bytes 要写的数据
     */
    private void startSettingSession(List<byte[]> bytes) {
        AsyncTask task = new SettingProgress(bytes, getApplicationContext());
        task.execute();
    }

    static class SettingProgress extends AsyncTask {
        List<byte[]> bytes;
        WeakReference<Context> context;
        boolean success = false;

        public SettingProgress(List<byte[]> bytes, Context context) {
            this.bytes = bytes;
            this.context = new WeakReference<>(context);
        }

        @Override
        protected Object doInBackground(Object[] objects) {
            try {
                FrameUtil.writeAllRegister(context.get(), bytes);
                success = true;
            } catch (FrameUtil.WriteRegisterNoBackException e) {
                success = false;
            }

            return success;
        }

        @Override
        protected void onPostExecute(Object o) {
            if (success) {
                context.get().sendBroadcast(new Intent(Actions.ACTION_WRITE_SUCCESS));
            } else {
                context.get().sendBroadcast(new Intent(Actions.ACTION_WRITE_FAIL));
            }
            isStateUpdateStoped = false;
            context.get().startActivity(new Intent()
                    .setClass(context.get(), Main2Activity.class)
                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
            super.onPostExecute(o);
        }
    }


    static private WriteThread writeThread = null;
    /**
     * 打开蓝牙Notify
     */
    private void openNotify() {
        BleManager.getInstance().notify(
                localBleDevice,
                FrameUtil.SERVICE_UUID,
                FrameUtil.CHARACTERISTIC_UUID,
                false,
                new BleNotifyCallback() {
                    @Override
                    public void onNotifySuccess() {
                        // 打开通知操作成功
                        Log.d("打开通知操作", "成功");
                        isBtConnected = true;
                        //((App)getApplication()).addDevHis(localBleDevice.getMac());
                        sendBroadcast(new Intent(Actions.ACTION_BLE_CONNECTED)
                                .putExtra("mac", localBleDevice.getMac()));
                        new GetRemoteState().start();
                        if (writeThread != null) {
                            writeThread.stopThread();
                            try {
                                writeThread.join();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                       writeThread = new WriteThread();
                       writeThread.start();
                    }

                    @Override
                    public void onNotifyFailure(BleException exception) {
                        // 打开通知操作失败
                        Log.d("打开通知操作", "失败:" + exception.toString());
                        sendBroadcast(new Intent(Actions.ACTION_RECONNECT));
                    }

                    /**
                     * 接收到数据
                     * @param data 数据
                     */
                    @Override
                    public void onCharacteristicChanged(byte[] data) {
                        // 打开通知后，设备发过来的数据将在这里出现
                        Log.d("接收到", data.length + "byte " + HexUtil.formatHexString(data));
                        System.arraycopy(data, 0, receivedata, runner, data.length);
                        runner += data.length;
                        if (data[0] == (byte) 0xff && data[1] == (byte) 0x41 && runner == 7) {
                            int crc = FrameUtil.crc16Check(receivedata, 5);
                            byte first = (byte) (crc & 0xff);
                            byte second = (byte) ((crc >> 8) & 0xff);
                            if (first == receivedata[5] && second == receivedata[6]) {
                                Log.d("CRC校验", "授权时间");
                                int remian = FrameUtil.getRemainTime(receivedata);
                                sendBroadcast(new Intent(Actions.ACTION_REMAINTIME).putExtra("data", remian));
                                runner = 0;
                            }
                        }
                        if (runner >= 7 && FrameUtil.crc16Check(receivedata, 8) == 0) {
                            byte[] back = Arrays.copyOf(receivedata, 8);
                            sendBroadcast(new Intent(Actions.ACTION_BACK_DATA)
                                    .putExtra("data", back));
                            backData = back;
                            runner = 0;
                        }
                        if (data[0] == (byte) 0xff && data[1] == (byte) 0x41 && runner > 7) {
                            int crc = FrameUtil.crc16Check(receivedata, runner);
                            if (0 == crc) {
                                Log.d("CRC校验", "密码");
                                sendBroadcast(new Intent(Actions.ACTION_DATA_UPDATE).putExtra("data", receivedata));
                                runner = 0;
                            }
                        }
                        registers:
                        if (runner > 100) {
                            int lenth = receivedata[2] + 5;
                            if (lenth < 0) {
                                runner = 0;
                                break registers;
                            }
                            int crc = FrameUtil.crc16Check(receivedata, lenth - 2);
                            byte first = (byte) (crc & 0xff);
                            byte second = (byte) ((crc >> 8) & 0xff);

                            if (first == receivedata[lenth - 2] && second == receivedata[lenth - 1]) {
                                Log.d("CRC校验成功", "寄存器");
                                sendBroadcast(new Intent(Actions.ACTION_DATA_UPDATE).putExtra("data", receivedata).putExtra("length", lenth));
                                Log.d("接收",
                                        HexUtil.formatHexString(receivedata).substring(0, lenth * 2));
                                runner -= lenth;
                                if (runner < 0) {
                                    runner = 0;
                                }
                                Log.d("CRC校验成功", String.format("0x%X:length:%d, 应为(%X,%X) => 收到(%X,%X) ThreadName:%s ThreadId:%d",
                                        receivedata[1], lenth, first, second, receivedata[lenth - 2],
                                        receivedata[lenth - 1], Thread.currentThread().getName(),
                                        Thread.currentThread().getId()));
                            } else {
                                Log.d("CRC校验失败", String.format("0x%X:length:%d, 应为(%X,%X) => 收到(%X,%X) ThreadName:%s ThreadId:%d",
                                        receivedata[1], lenth, first, second, receivedata[lenth - 2],
                                        receivedata[lenth - 1], Thread.currentThread().getName(),
                                        Thread.currentThread().getId()));
                            }
                        }
                        //要满了就丢掉
                        if (runner >= RECEIVEBUFFER_LENGTH - 20 - 1) {
                            runner = 0;
                        }
                    }
                });
    }


    /**
     * 广播接收者
     */
    private class BluetoothServiceReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction() == null) {
                return;
            }
            String s = intent.getAction();
            if (Actions.ACTION_LINKBT_MAC.equals(s)) {
                macToLink = intent.getStringExtra("mac_input");
                Log.d("FastBleService", "MAC is" + macToLink);
                connectByMac(macToLink);

            } else if (Actions.ACTION_REQUEST_LOCATION_PERMISSION_SUCCESS.equals(s)) {//申请权限成功
                startScan();
            } else if (Actions.ACTION_TIMER_TRIG.equals(s)) {
                if (!isStateUpdateStoped) {
                    //定时发读数据指令
                    FrameUtil.oneTurnRequest(getApplicationContext(), timer);
                }

            } else if (Actions.ACTION_SERVICE_SELECTED.equals(s)) {
                String serviceuuid = intent.getStringExtra("uuid");
                for (BluetoothGattService service : localservices
                ) {
                    String suuid = service.getUuid().toString();
                    if (suuid.equals(serviceuuid)) {
                        localService = service;
                        sendBroadcast(new Intent(Actions.ACTION_CHAR_RETURN).putExtra("uuid", getUuidFromchars(service.getCharacteristics())));
                    }
                }

            } else if (Actions.ACTION_CHAR_SELECTED.equals(s)) {
                List<BluetoothGattService> serviceList = BleManager.getInstance().getBluetoothGattServices(localBleDevice);
                for (BluetoothGattService serv : serviceList
                ) {
                    if (serv.getUuid().toString().equals(FrameUtil.SERVICE_UUID)) {
                        localService = serv;
                    }
                }
                if (localService == null) {
                    return;
                }

                List<BluetoothGattCharacteristic> characteristicList = BleManager.getInstance().getBluetoothGattCharacteristics(localService);
                for (BluetoothGattCharacteristic chara : characteristicList
                ) {
                    if (chara.getUuid().toString().equals(FrameUtil.CHARACTERISTIC_UUID)) {
                        localCharacteristic = chara;
                    }
                }
                if (localCharacteristic == null) {
                    return;
                }

                openNotify();

            } else if (Actions.ACTION_WRITE.equals(s)) {
                if (localBleDevice == null || localService == null || localCharacteristic == null) {
                    return;
                }
                sendMsgQueue.offer(
                        (WriteWithCallback) intent.getSerializableExtra("writebytes"));
            } else if (Actions.ACTION_READ.equals(s)) {
                if (localBleDevice == null || localService == null || localCharacteristic == null) {
                    return;
                }
                BleManager.getInstance().read(localBleDevice,
                        localService.getUuid().toString(),
                        localCharacteristic.getUuid().toString(),
                        new BleReadCallback() {
                            @Override
                            public void onReadSuccess(byte[] data) {
                                Log.d("读取到", data.length + "byte" + Arrays.toString(data));
                            }

                            @Override
                            public void onReadFailure(BleException exception) {
                                Log.d("读取失败", exception.toString());
                            }
                        });

            } else if (Actions.ACTION_SETTING.equals(s)) {
                isStateUpdateStoped = true;
                try {
                    List<byte[]> datalist = (List<byte[]>) intent.getSerializableExtra("settingdata");
                    startSettingSession(datalist);
                } catch (Exception e) {
                    e.printStackTrace();
                    isStateUpdateStoped = false;
                }

            } else if (Actions.ACTION_STARTSCAN.equals(s)) {
                startScan();
            } else if (Actions.ACTION_BLE_DISCONNECT.equals(s)) {
                isBtConnected = false;
            } else if (Actions.ACTION_RECONNECT.equals(s)) {
                Log.d("重新连接", macToLink);
                connectByMac(macToLink);
            } else if (Actions.ACTION_STOPREAD.equals(s)) {
                stopread = true;
            } else if (Actions.ACTION_STARTREAD.equals(s)) {
                stopread = false;
            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(s)) {
                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                switch (state) {
                    case BluetoothAdapter.STATE_TURNING_ON:
                        startScan();
                        break;
                    case BluetoothAdapter.STATE_TURNING_OFF:
                        break;
                    default:
                        break;
                }
            } else if (Actions.ACTION_FIRST_READ.equals(s)) {
                runner = 0;
            }
        }
    }
}
